using System;
using System.Collections.Generic;
using System.Text;
using System.Xml;
using System.Windows.Forms;
using System.Data;
using MacomberMap.Common.Components;
using System.IO;
using MacomberMap.Common.Internals;
using System.Drawing;
using MacomberMap.Common.Types;
using MacomberMap.Common.Permissions;

namespace MacomberMap.Common.Database_Interface
{
    /// <summary>
    /// This class handles the connection between the MM Loader and its associated back-end database
    /// </summary>
    public abstract class MM_Database: MM_Serializable
    {
        #region Variable declarations
        /// <summary>The name of the database connection (user-defined)</summary>
        public String Name;

        /// <summary>
        /// Get/Set whether the database is currently the default one
        /// </summary>
        public bool Default
        {
            get { return MM_Configuration.DefaultDatabase == this; }
            set
            {
                if (value)
                    MM_Configuration.DefaultDatabase = this;
                else if (MM_Configuration.DefaultDatabase == this)
                    MM_Configuration.DefaultDatabase = null;
            }
        }

        /// <summary>
        /// Get/Set whether the database is currently the master one
        /// </summary>
        public bool Master
        {
            get { return MM_Configuration.MasterDatabase == this; }
            set
            {
                if (value)
                    MM_Configuration.MasterDatabase= this;
                else if (MM_Configuration.MasterDatabase== this)
                    MM_Configuration.MasterDatabase = null;
            }
        }
        #endregion

        #region Initializers
        /// <summary>
        /// Initialize a new database
        /// </summary>
        /// <param name="BaseElement"></param>
        public MM_Database(XmlElement BaseElement):base(BaseElement)
        {
            this.Name = BaseElement.Attributes["Name"].Value;            
        }

        /// <summary>
        /// Initialize a new database
        /// </summary>
        /// <param name="Name"></param>
        public MM_Database(String Name)
        {
            this.Name = Name;
        }

        /// <summary>
        /// Create a new database connection based on the requested XML element
        /// </summary>
        /// <param name="BaseElement"></param>
        /// <returns></returns>
        public static MM_Database CreateDatabaseConnection(XmlElement BaseElement)
        {
            if (BaseElement.Attributes["Type"].Value == "Oracle")
                return new MM_Database_Oracle(BaseElement);
            else
                throw new InvalidDataException("Unable to connect to database of type " + BaseElement.Attributes["Type"].Value);
        }
        #endregion

        #region User interface interactions
        /// <summary>
        /// Configure the "existing schema" tab in the main UI to reflect only Oracle options
        /// </summary>        
        /// <param name="DbType">The database type</param>
        /// <param name="cmbDbName">The combo box for database name</param>
        /// <param name="txtUsername">The combo box for username</param>
        /// <param name="txtPassword">The combo box for password</param>
        /// <param name="txtSchema">The combo box for schema</param>
        public static void ConfigureExistingSchemaUI(String DbType, ComboBox cmbDbName, TextBox txtUsername, TextBox txtPassword, ComboBox txtSchema)
        {
            cmbDbName.Visible = DbType == "Oracle";
            txtUsername.Visible = DbType == "Oracle";
            txtPassword.Visible = DbType == "Oracle";
            txtSchema.Visible = DbType != "Oracle";
        }
        #endregion

        #region Abstract members
        /// <summary>Open the database connection</summary>
        public abstract void Open();

        /// <summary>Close the database connection</summary>
        public abstract void Close();

        /// <summary>Retrieve the connection state of the database connection</summary>
        public abstract ConnectionState State { get;}

        /// <summary>Retrieve the database connection type (matching XML)</summary>
        public abstract String Type { get;  set;}

        /// <summary>Display the connection statistics for our database</summary>        
        public abstract DataTable ConnectionStats();
        
        /// <summary>Load our collection of companies</summary>
        public abstract void LoadCompanies();

        /// <summary>Load our collection of counties</summary>
        public abstract void LoadCounties();

        /// <summary>Save our state coordinates to the database</summary>
        public abstract void SaveStateCoordinates();

        /// <summary>Save our county information to the database</summary>
        public abstract void SaveCounties();

        /// <summary>
        /// Save a boundary to the database
        /// </summary>
        /// <param name="Boundary">The boundary to be saved</param>
        public abstract void SaveBoundary(MM_Boundary Boundary);

        /// <summary>Load our lines from the database</summary>
        public abstract void LoadLines();

        /// <summary>Load our DC ties from the database, and merge them with the lines they are matched to</summary>
        public abstract void MergeDCTies();

        /// <summary>Load our substations from the database</summary>
        public abstract void LoadSubstations();     

        /// <summary>Load our KV levels from the database</summary>
        public abstract void LoadKVLevels();


        
        /// <summary>Save our substation latitude/longitude information to the database</summary>
        public abstract void SaveSubstationCoordinates();

        /// <summary>Erase CIM-specific data from the database</summary>
        public abstract void BlankDatabase();

        /// <summary>
        /// Create our target tables in the database
        /// </summary>
        /// <param name="DbConnection">The database connection</param>
        public abstract void CreateTables(Object DbConnection);

        /// <summary>Save our list of counties' websites</summary>
        /// <param name="Filename">The file name containing the websites</param>
        public abstract void SaveCountyWebsites(String Filename);

        /// <summary>
        /// Save our configuration parameters to an opened XML stream
        /// </summary>
        /// <param name="xW">The XML stream to be written</param>
        public abstract void SaveConfigurationParameters(XmlTextWriter xW);

        /// <summary>
        /// Save a map tile to the database
        /// </summary>
        /// <param name="NewTile">The new map tile to be added</param>
        public abstract void SaveMapTile(MM_MapTile NewTile);

        /// <summary>
        /// Load a map tile from the database
        /// </summary>
        /// <param name="mapType">The map type to be retrieved</param>
        /// <param name="TileXY">The tile X/Y</param>
        /// <param name="ZoomLevel">The Zoom level of the map tile</param>
        /// <param name="Tile">The tile to be saved</param>
        /// <returns></returns>
        public abstract bool LoadMapTile(MM_MapTile.MapType mapType, Point TileXY, int ZoomLevel, out Bitmap Tile);

        /// <summary>
        /// Lookup a user in the database
        /// </summary>
        /// <param name="UserName">The user name to search for</param>
        /// <returns></returns>        
        public abstract int LookupUser(string UserName);

        /// <summary>
        /// Load a role's display and permissions XML
        /// </summary>
        /// <param name="UserRole">The user role to be loaded</param>
        /// <param name="DefaultView">The number corresponding to the role default view</param>
        /// <param name="PermissionsXML">The permissions XML parameter</param>
        public abstract void LoadRole(int UserRole, out int DefaultView, out string PermissionsXML);

        /// <summary>Load the weather and load zone collection</summary>
        public abstract void LoadZones();

        /// <summary>
        /// Load all roles, users and databases
        /// </summary>
        /// <returns></returns>
        public abstract DataSet LoadUsersAndRoles();

        /// <summary>
        /// Load our collection of element types
        /// </summary>
        public abstract void LoadElementTypes();

        /// <summary>
        /// Load our collection of Event types
        /// </summary>
        public abstract void LoadEventTypes();

        /// <summary>
        /// Load all views
        /// </summary>
        /// <param name="UserRole">The currently active user role</param>
        /// <param name="DefaultView">The default view for this role</param>
        public abstract void LoadViews(int UserRole, int DefaultView);

        /// <summary>
        /// Load our collection of one-lines (type, TEID, name) into memory
        /// </summary>
        /// <returns></returns>
        public abstract DataTable LoadOneLines();

        /// <summary>
        /// Load the one-line display for a particular TEID into memory
        /// </summary>
        /// <param name="TEID">The TEID to be loaded</param>
        /// <returns></returns>
        public abstract String LoadOneLine(UInt64 TEID);

        /// <summary>
        /// Load the one-line display for a particular name into memory
        /// </summary>
        /// <param name="Name"></param>
        /// <returns></returns>
        public abstract String LoadOneLine(String Name);

        /// <summary>
        /// Upload a one-line into the database
        /// </summary>
        /// <param name="BaseElement">The element around which the one-line is based</param>
        /// <param name="OneLineXML">The XML configuration for the one-line</param>
        public abstract void SaveOneLine(MM_Element BaseElement, String OneLineXML);

        /// <summary>
        /// Locate an element by TEID
        /// </summary>
        /// <param name="TEID">The TEID of the element</param>
        /// <returns></returns>
        public abstract MM_Element LocateElement(UInt64 TEID);


        /// <summary>
        /// Locate an element by TEID and element type
        /// </summary>
        /// <param name="TEID">The TEID of the element</param>
        /// <param name="ElemType">The element type to search for</param>
        /// <returns></returns>
        public abstract MM_Element LocateElement(UInt64 TEID, MM_Element_Type ElemType);

        /// <summary>
        /// Locate an element by name and element type
        /// </summary>
        /// <param name="SubstationName">The name of the substation</param>
        /// <param name="Name">The element's name</param>
        /// <param name="ElemType">The element's type</param>
        /// <returns></returns>
        public abstract MM_Element LocateElement(String SubstationName, String Name, MM_Element_Type ElemType);

        /// <summary>
        /// Load all elements connected around an element (e.g., elements w/in a substation, or traces around a trace elemement)
        /// </summary>
        /// <param name="BaseElement">The element around which the tracing should occur</param>
        /// <returns></returns>
        public abstract List<MM_Element> LoadElements(MM_Element BaseElement);
        
        #endregion

        #region Schmea creation
        /// <summary>
        /// Create a new Oracle database schema to hold the MM loader data
        /// </summary>
        /// <param name="DbType">The database type</param>
        /// <param name="ConnectionName">The name of the connection</param>
        /// <param name="AdminUser">Administrator's user name</param>
        /// <param name="AdminPassword">Administrator's password</param>
        /// <param name="ServerName">Server TNS Name</param>
        /// <param name="UserName">New Schema name / User Name</param>
        /// <param name="UserPassword">New User password</param>
        /// <param name="DbSize">The current size of the database</param>
        /// <param name="MaxSize">The maximum size of the database</param>
        /// <param name="DbPath">The path to the Oracle database file</param>
        /// <param name="StepSize">The database incremental size</param>
        public static MM_Database CreateSchema(String DbType, String ConnectionName, String AdminUser, String AdminPassword, String ServerName, String UserName, String UserPassword, String DbPath, Decimal DbSize, Decimal MaxSize, Decimal StepSize)
        {
            if (DbType == "Oracle")
                return MM_Database_Oracle.CreateSchema(ConnectionName, AdminUser, AdminPassword, ServerName, UserName, UserPassword, DbPath, DbSize, MaxSize, StepSize);
            else
                throw new InvalidDataException("Unable to create schema for database type " + DbType);
            
            
        }
        #endregion                                                      
    
        
        
    
        
    }
}
